package mips.instructions;

import mips.Main;

/**
 * <code>BGTZ</code> instruction<br/>
 * Branch On Greater Than Zero<br/>
 * @author jnmartin84@gmail.com
 */
public class BGTZ extends Instruction {

	private static final BGTZ INSTANCE = new BGTZ();
	private static final String INSTRUCTION_NAME = "BGTZ";

	private BGTZ(){}

	public static final BGTZ getInstance() {
		return INSTANCE;
	}

	/**
	 * <b>Format:</b><br/>
	 * BGTZ rs, offset<br/><br/>
	 * <b>Description:</b><br/>
	 * A branch target address is computed from the sum of the address of the<br/>
	 * instruction in the delay slot and the 16-bit offset, shifted left two bits and<br/>
	 * sign-extended. The contents of general register rs are compared to zero. If<br/>
	 * the contents of general register rs have the sign bit cleared and are not<br/>
	 * equal to zero, then the program branches to the target address, with a<br/>
	 * delay of one instruction.<br/><br/>
	 * <b>Operation:</b><br/>
	 * T: target &larr; (offset<sub>15</sub>)<sup>14</sup> || offset || 0<sup>2</sup><br/>
	 * condition &larr; (GPR[rs]<sub>31</sub> = 0) and (GPR[rs] &ne; 0<sup>32</sup>)<br/>
	 * T+1: if condition then<br/>
	 * PC &larr; PC + target<br/>
	 * endif
	 */
	@Override
	public final void execute(final int instruction) {
		
		final int rs = (instruction >> 21) & 0x0000001F;
		final int offset = Instruction.signExtendH(instruction & 0x0000FFFF) << 2;

		if(mips.R4300i.GPR[rs] > 0) {

			mips.R4300i.PC = mips.R4300i.nPC;
			mips.R4300i.nPC = mips.R4300i.PC + offset;

//			mips.CPU.DELAY_SLOT_EXEC = true;
			
			if(Main.tracing) {
				mips.R4300i.targets.put(mips.R4300i.nPC,null);
			}
		}
		else {

//			mips.CPU.DELAY_SLOT_EXEC = false;
			
			mips.R4300i.PC = mips.R4300i.nPC;
			mips.R4300i.nPC = mips.R4300i.PC + 4;
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String emit(final int instruction) {

		final int rs = (instruction >> 21) & 0x0000001F;
		final int offset = Instruction.signExtendH(instruction & 0x0000FFFF) << 2;

		return	"		if(mips.CPU.GPR["+rs+"] > 0) {\n" + 
				"			\n" + 
				"			mips.CPU.PC = mips.CPU.nPC;\n" + 
				"			mips.CPU.nPC = mips.CPU.PC + "+offset+";\n" +
				"		}\n" + 
				"		else {\n" + 
				"			\n" + 
				"			mips.CPU.PC = mips.CPU.nPC;\n" + 
				"			mips.CPU.nPC = mips.CPU.PC + 4;\n" + 
				"		}\n";
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getName(final int instruction) {
		return getName();
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getName() {
		return INSTRUCTION_NAME;
	}
}